/** 
* Keyboard device, tracks keyboard interaction and fires event delegates. Possible events are onkeydown, onkeychange and onkeyup.
* @extends Kwik.Object
* @requires Kwik.Object
* @created 8:59 AM 4/22/2008
* @modified 8:59 AM 4/22/2008
* @singleton 
*/
Kwik.Ui.Devices.Keyboard = 
{
	/** Keycode of last pressed key @type Number */
	lastKey: -1,
	/** Keycode of current pressed key @type Number */
	key: -1,
	/** Indication whether the 'shift' key is pressed @type Number */
	shiftKey: false,
	/** Indication whether the 'alt' key is pressed @type Number */
	altKey: false,
	/** Indication whether the 'ctrl' key is pressed @type Number */
	ctrlKey: false,
	/** List of trackers which receive mouse status changes @type Kwik.Ui.Devices.MouseTracker[] */
	trackers: {},
	/** Amount of trackers registered */
	trackerCount: 0,

	/** Add a Keyboard tracker to the receive status changes */
	register: function Keyboard_register(tracker)
	{
		if(Kwik.Ui.Devices.Keyboard.trackerCount == 0)
		{
			Kwik.Ui.Devices.Keyboard._attachEvents();
		}

		var id = "tracker" + tracker.ptr.toString();
		if(id in Kwik.Ui.Devices.Keyboard.trackers){return;}

		Kwik.Ui.Devices.Keyboard.trackers[id] = tracker;
		Kwik.Ui.Devices.Keyboard.trackerCount++;
	},

	/** Remove a Keyboard tracker */
	unregister: function Keyboard_unregister(tracker)
	{

		var id = "tracker" + tracker.ptr.toString();
		if(id in Kwik.Ui.Devices.Keyboard.trackers)
		{
			delete Kwik.Ui.Devices.Keyboard.trackers[id];
			Kwik.Ui.Devices.Keyboard.trackerCount--;
		}
		else
		{
			return;
		}
		if(Kwik.Ui.Devices.Keyboard.trackerCount == 0)
		{
			Kwik.Ui.Devices.Keyboard._detachEvents();
		}
	},
	
	/** Attaches the Keyboard status listeners to the document */
	_attachEvents: function Keyboard__attachEvents()
	{
		Kwik.Page.log.write("Kwik.Ui.Devices.Keyboard._attachEvents: Attaching events.");
		Kwik.Utility.attachEvent(document, "onkeydown", Kwik.Ui.Devices.Mouse._keyDown);
		Kwik.Utility.attachEvent(document, "onkeyup", Kwik.Ui.Devices.Mouse._keyUp);
	},

	/** Detaches the mouse status listeners from the document */
	_detachEvents: function Keyboard__detachEvents()
	{
		Kwik.Page.log.write("Kwik.Ui.Devices.Keyboard._detachEvents: Detaching events.");
		Kwik.Utility.detachEvent(document, "onkeydown", Kwik.Ui.Devices.Mouse._keyDown);
		Kwik.Utility.detachEvent(document, "onkeyup", Kwik.Ui.Devices.Mouse._keyUp);
	},

	/** Handler for onkeydown events */
	_keyDown: function(e)
	{
		e = e || event;
		Kwik.Ui.Devices.Keyboard.key = e.keyCode;
		Kwik.Ui.Devices.Keyboard.shiftKey = e.shiftKey;
		Kwik.Ui.Devices.Keyboard.ctrlKey = e.ctrlKey;
		Kwik.Ui.Devices.Keyboard.altKey = e.altKey;

		for(e in Kwik.Ui.Devices.Mouse.trackers)
		{
			Kwik.Ui.Devices.Mouse.trackers[e].setKeys(
				Kwik.Ui.Devices.Keyboard.key,
				Kwik.Ui.Devices.Keyboard.shiftKey,
				Kwik.Ui.Devices.Keyboard.ctrlKey,
				Kwik.Ui.Devices.Keyboard.altKey
			);
		}

	},

	/** Handler for onkeydown events */
	_keyUp: function(e)
	{
		e = e || event;
		Kwik.Ui.Devices.Keyboard.lastKey = Kwik.Ui.Devices.Keyboard.key;
		Kwik.Ui.Devices.Keyboard.key = -1;
		Kwik.Ui.Devices.Keyboard.shiftKey = e.shiftKey;
		Kwik.Ui.Devices.Keyboard.ctrlKey = e.ctrlKey;
		Kwik.Ui.Devices.Keyboard.altKey = e.altKey;

		for(e in Kwik.Ui.Devices.Mouse.trackers)
		{
			Kwik.Ui.Devices.Mouse.trackers[e].setKeys(
				Kwik.Ui.Devices.Keyboard.key,
				Kwik.Ui.Devices.Keyboard.shiftKey,
				Kwik.Ui.Devices.Keyboard.ctrlKey,
				Kwik.Ui.Devices.Keyboard.altKey
			);
		}

	}
};

/** 
* Keyboard change tracker, tracks keyboard interaction
* @base Kwik.Object 
* @requires Kwik.Object
* @requires Kwik.Ui.Devices.Keyboard
* @created 11:50 AM 7/13/2009
* @modified 11:50 AM 7/13/2009
* @constructor 
*/
Kwik.Ui.Devices.KeyboardTracker = function(config)
{
	/** @ignore */
	Kwik.Utility.extend(this, "Kwik.Object");
	this.__class.push("Kwik.Ui.Devices.KeyboardTracker");

	/** Keycode of last pressed key @type Number */
	this.lastKey = -1;
	/** Keycode of current pressed key @type Number */
	this.key = -1;
	/** Indication whether the 'shift' key is pressed @type Number */
	this.shiftKey = false;
	/** Indication whether the 'alt' key is pressed @type Number */
	this.altKey = false;
	/** Indication whether the 'ctrl' key is pressed @type Number */
	this.ctrlKey = false;
	/** Indication whether the tracker is tracking or not @type Boolean */
	this.isTracking = false;

	/** Start tracking mouse interaction, optionally a mouse event can be passed to initialize the tracker properties */
	this.start = function KeyboardTracker_start(evt)
	{
		if(this.isTracking === true){return;}
		if(evt)
		{
			Kwik.Ui.Devices.Mouse.x = this.x = evt.clientX + Kwik.Ui.Devices.Screen.getScrollLeft();
			Kwik.Ui.Devices.Mouse.y = this.y = evt.clientY + Kwik.Ui.Devices.Screen.getScrollTop();
			Kwik.Ui.Devices.Mouse.button = this.button = Kwik.BrowserInfo.internetExplorer? Kwik.Ui.Devices.Mouse._ieButtons["b" + evt.button.toString()]: evt.button;
		}
		this.fireEvent("onbeforestart");

		Kwik.Ui.Devices.Keyboard.register(this);
		this.isTracking = true;

		this.fireEvent("onstart");
	};

	/** Stop tracking */
	this.stop = function KeyboardTracker_stop()
	{
		if(this.isTracking === false){return;}
		this.fireEvent("onbeforestop");

		Kwik.Ui.Devices.Keyboard.unregister(this);
		this.isTracking = false;

		this.fireEvent("onstop");
	};

	/** Set the keys for this tracker */
	this.setKeys = function Kyboard_setKeys(key, shiftKey, ctrlKey, altKey)
	{
		this.fireEvent("onbeforechange", [this.key, key]);
		this.lastKey = this.key;
		this.key = key;
		this.shiftKey = shiftKey;
		this.ctrlKey = ctrlKey;
		this.altKey = altKey;
		this.fireEvent("onchange", [this.key]);
	};

	/** Configures this mousetracker object */
	this.configure = function KeyboardTracker_configure(config)
	{
		config = this.Kwik$Object.configure(config);
		if(Kwik.Type.isNumber(config.key)){this.key = config.key;}
		if(Kwik.Type.isNumber(config.lastKey)){this.lastKey = config.lastKey;}
		if(Kwik.Type.isBoolean(config.shiftKey)){this.shiftKey = config.shiftKey;}
		if(Kwik.Type.isBoolean(config.altKey)){this.altKey = config.altKey;}
		if(Kwik.Type.isBoolean(config.ctrlKey)){this.ctrlKey = config.ctrlKey;}
	};

	/** Get the string represtation of current keyboard state */
	this.toString = function Keyboard_toString()
	{
		return [
			"lastKey=" + this.lastKey,
			"key=" + this.key,
			"shiftKey=" + this.shifKey,
			"altKey=" + this.altKey,
			"ctrlKey=" + this.ctrlKey
			].join(";") + ";";
	};

	/** Event fired before a key changes */
	this.onbeforechange = function(oldkey, newkey){};
	/** Event fired when a key changes */
	this.onchange = function(key){};

	/** @ignore */
	this.main = function KeyboardTracker_main(config)
	{
		if(config){this.configure(config);}
	}; this.main(config);
}